package com.eastfair.config.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.eastfair.annotation.base.LanguageTypeEnum;
import com.eastfair.annotation.base.SubjectTypeEnum;
import com.eastfair.boot.service.SuperCacheServiceImpl;
import com.eastfair.cache.projectcore.FormFieldCacheKeyBuilder;
import com.eastfair.cache.redis.RedisOps;
import com.eastfair.config.contant.ConfigContant;
import com.eastfair.config.contant.FormFieldContant;
import com.eastfair.config.dao.FormFieldMapper;
import com.eastfair.config.dto.FormFieldCheckDTO;
import com.eastfair.config.dto.FormFieldDTO;
import com.eastfair.config.entity.FormField;
import com.eastfair.config.service.FormFieldService;
import com.eastfair.config.vo.FormFieldVO;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.constant.RedisKeyConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.code.ExceptionCode;
import com.eastfair.core.model.CacheKeyBuilder;
import com.eastfair.core.snowflake.DefaultUidGenerator;
import com.eastfair.core.utils.ConvertUtil;
import com.eastfair.core.utils.StringUtils;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 业务实现类
 *
 * </p>
 *
 * @author zjn
 * @date 2021-08-10
 */
@Slf4j
@Service
@DS("#thread.tenant")
public class FormFieldServiceImpl extends SuperCacheServiceImpl<FormFieldMapper, FormField> implements FormFieldService {

    @Autowired
    private RedisOps redisOps;

    @Override
    protected CacheKeyBuilder cacheKeyBuilder() {
        return new FormFieldCacheKeyBuilder();
    }

    /**
     * 处理新增相关处理
     *
     * @param model 实体
     * @return 是否成功
     */
    @Override
    protected R<Boolean> handlerSave(FormField model) {
        //雪花ID,不需要分库分表
//        SelfUidDto selfUidDto = new SelfUidDto();
//        model.setId(selfUidService.getUid(selfUidDto));
        model.setId(DefaultUidGenerator.getUid(ContextUtil.getProjectId()));
        model.setProjectId(ContextUtil.getProjectId());
        return R.successDef();
    }

    @Override
    public R<List<FormFieldVO>> getBySubjectType(FormFieldDTO formFieldDTO) {
        if (StringUtils.isBlank(formFieldDTO.getSubjectType()) || Objects.isNull(formFieldDTO.getExhibitionId())) {
            R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }
        formFieldDTO.setProjectId(ContextUtil.getProjectId());
        List<FormField> list = getBySubjectTypeInside(formFieldDTO);

        //暂时不要
//        if (list == null || list.isEmpty()) {
//            // 从模板展会拷贝基础配置
//            copyFormTemplate(formFieldDTO);
//            list = getByShowTypeInside(formFieldDTO);
//        }
        return R.success(ConvertUtil.convertList(list, FormFieldVO.class));
    }

    @Override
    public List<FormField> getBySubjectTypeInside(FormFieldDTO formFieldDTO) {
        QueryWrapper<FormField> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(FormField::getProjectId, ContextUtil.getProjectId())
                .eq(FormField::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(FormField::getExhibitionId, formFieldDTO.getExhibitionId())
                .eq(FormField::getSubjectType, SubjectTypeEnum.get(formFieldDTO.getSubjectType()))
                .orderByAsc(FormField::getSequence).orderByAsc(FormField::getKeyword);

        // 是否用于完善信息
        if (!Objects.isNull(formFieldDTO.getIsPerfectInfo())) {
            wrapper.lambda().eq(FormField::getIsPerfectInfo, formFieldDTO.getIsPerfectInfo());
        }

        // 是否是详情字段
        if (!Objects.isNull(formFieldDTO.getIsDetails())) {
            wrapper.lambda().eq(FormField::getIsDetails, formFieldDTO.getIsDetails());
        }

        // 启用
        if (!Objects.isNull(formFieldDTO.getIsEnabled())) {
            wrapper.lambda().eq(FormField::getIsEnabled, formFieldDTO.getIsEnabled());
        }

        // 分组
        if (Objects.nonNull(formFieldDTO.getFieldGroup())) {
            wrapper.lambda().eq(FormField::getFieldGroup, formFieldDTO.getFieldGroup());
        }

        // 语言
        if (!StringUtils.isBlank(formFieldDTO.getLanguageType())) {
            wrapper.lambda().eq(FormField::getLanguageType, LanguageTypeEnum.parse(formFieldDTO.getLanguageType()));
        }

        // 是否是线下字段处理
        if (!Objects.isNull(formFieldDTO.getIsOffline())) {
            wrapper.lambda().eq(FormField::getIsOffline, formFieldDTO.getIsOffline());
        }

        // 分组
        if (!StringUtils.isBlank(formFieldDTO.getFieldName())) {
            wrapper.lambda().and(likeWrapper -> likeWrapper.like(FormField::getFieldName, formFieldDTO.getFieldName())
                    .or().like(FormField::getFieldEnName, formFieldDTO.getFieldName())
            );
        }

        return list(wrapper);
    }

    @Override
    public R<Boolean> checkFormFieldInfo(FormFieldCheckDTO formFieldCheckDTO) {
        // 实体/类名为空 校验失败
        if (Objects.isNull(formFieldCheckDTO.getObject()) || Objects.isNull(formFieldCheckDTO.getFormFieldDTO())
                || StringUtils.isBlank(formFieldCheckDTO.getClassName())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 获取相关表单
        List<FormField> formFieldList = getBySubjectTypeInside(formFieldCheckDTO.getFormFieldDTO());

        // 表单为空，校验成功
        if (formFieldList == null || formFieldList.isEmpty()) {
            return R.success(Boolean.TRUE);
        }

        Class<?> entityClass = null;
        try {
            entityClass = Class.forName(formFieldCheckDTO.getClassName());
        } catch (ClassNotFoundException e) {
            log.error(e.getMessage());
            return R.fail(e.getMessage());
        }
        // 表单校验
        for (FormField formField : formFieldList) {
            String value = "";

            R<String> valueStr = getValueStr(formField.getKeyword(), formFieldCheckDTO.getObject(), entityClass);
            if (valueStr.getIsSuccess()) {
                value = valueStr.getData();
            } else {
                return R.fail(valueStr.getMsg());
            }

            if (BusinessConstant.YES == formField.getIsRequired()) {
                if (StringUtils.isBlank(value)) {
                    return R.success(Boolean.FALSE);
                }
            }

            if (!Objects.isNull(formField.getInputLength())) {
                if (formField.getInputLength() < value.length()) {
                    return R.success(Boolean.FALSE);
                }
            }

        }
        return R.success(Boolean.TRUE);
    }

    /**
     * 从模板展会拷贝配置到当前展会
     *
     * @param formFieldDTO 配置类型
     */
    private void copyFormTemplate(FormFieldDTO formFieldDTO) {
        QueryWrapper<FormField> temWrapper = new QueryWrapper<>();
        temWrapper.lambda().eq(FormField::getExhibitionId, FormFieldContant.TEMPLETE_EXHIBITION_ID)
                .orderByAsc(FormField::getSequence);
        List<FormField> temList = list(temWrapper);
        temList.forEach(formField -> {
            formField.setProjectId(ContextUtil.getProjectId());
            formField.setExhibitionId(ContextUtil.getExhibitionId());
            formField.setId(DefaultUidGenerator.getUidOfProjectId(ContextUtil.getProjectId()));
            formField.setCreateTime(null);
            formField.setUpdateTime(null);
        });
        saveBatch(temList);
    }

    @Override
    public R<Boolean> saveFormField(FormFieldDTO formFieldDTO) {
        formFieldDTO.setProjectId(ContextUtil.getProjectId());
        redisOps.del(String.format(RedisKeyConstant.FORM_FIELD_PERFECT_INFO_REDIS_KEY, formFieldDTO.getSubjectType(),
                LanguageTypeEnum.get(formFieldDTO.getLanguageType()), ContextUtil.getProjectId(), formFieldDTO.getExhibitionId()));
        redisOps.del(String.format(RedisKeyConstant.FORM_FIELD_DETAIL_REDIS_KEY, formFieldDTO.getSubjectType(),
                LanguageTypeEnum.get(formFieldDTO.getLanguageType()), ContextUtil.getProjectId(), formFieldDTO.getExhibitionId()));
        return R.success(save(BeanUtil.copyProperties(formFieldDTO, FormField.class)));
    }

    @Override
    public R<Boolean> updateFormField(FormFieldDTO formFieldDTO) {
        if (Objects.isNull(formFieldDTO.getId())) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }
        FormField formField = getById(formFieldDTO.getId());
        if (Objects.isNull(formField)) {
            return R.fail(ExceptionCode.ERROR_NULL_ID);
        }

        String subjectTye = formField.getSubjectType();
        if (!StringUtils.isBlank(formFieldDTO.getSubjectType())) {
            subjectTye = formFieldDTO.getSubjectType();
        }

        String languageType = formField.getLanguageType();
        if (!StringUtils.isBlank(formFieldDTO.getLanguageType())) {
            languageType = formFieldDTO.getLanguageType();
        }

        Long exhibitionId = formField.getExhibitionId();
        if (Objects.nonNull(formFieldDTO.getExhibitionId())) {
            exhibitionId = formFieldDTO.getExhibitionId();
        }

        redisOps.del(String.format(RedisKeyConstant.FORM_FIELD_PERFECT_INFO_REDIS_KEY, subjectTye,
                LanguageTypeEnum.get(languageType), ContextUtil.getProjectId(), exhibitionId));
        redisOps.del(String.format(RedisKeyConstant.FORM_FIELD_DETAIL_REDIS_KEY, subjectTye,
                LanguageTypeEnum.get(languageType), ContextUtil.getProjectId(), exhibitionId));

        return R.success(updateById(BeanUtil.copyProperties(formFieldDTO, FormField.class)));
    }

    @Override
    @GlobalTransactional(name = "copyFormFieldList", rollbackFor = Exception.class)
    public R<Boolean> copyFormFieldList(FormFieldDTO formFieldDTO) {
        if (Objects.isNull(formFieldDTO) || Objects.isNull(formFieldDTO.getExhibitionId())
                || StringUtils.isBlank(formFieldDTO.getSubjectType(), formFieldDTO.getLanguageType())) {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }
        // 查询原始表单列表
        QueryWrapper<FormField> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(FormField::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(FormField::getProjectId, ContextUtil.getProjectId())
                .eq(FormField::getExhibitionId, formFieldDTO.getExhibitionId())
                .eq(FormField::getSubjectType, formFieldDTO.getSubjectType())
                .eq(FormField::getLanguageType, formFieldDTO.getLanguageType());
        List<FormField> list = list(queryWrapper);
        if (CollectionUtil.isEmpty(list)) {
            return R.fail(ExceptionCode.NOT_FOUND);
        }
        // 获取目标语言环境
        LanguageTypeEnum copyToLanguage;
        if (LanguageTypeEnum.CN.eq(formFieldDTO.getLanguageType())) {
            copyToLanguage = LanguageTypeEnum.EN;
        } else if (LanguageTypeEnum.EN.eq(formFieldDTO.getLanguageType())) {
            copyToLanguage = LanguageTypeEnum.CN;
        } else {
            return R.fail(ExceptionCode.ERROR_NULL_PARAMS);
        }

        // 删除
        UpdateWrapper<FormField> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(FormField::getProjectId, ContextUtil.getProjectId())
                .eq(FormField::getExhibitionId, formFieldDTO.getExhibitionId())
                .eq(FormField::getSubjectType, formFieldDTO.getSubjectType())
                .eq(FormField::getLanguageType, copyToLanguage)
                .set(FormField::getIsDeleted, BusinessConstant.DELETE_YES);
        update(updateWrapper);

        // 拷贝
        List<Long> ids = DefaultUidGenerator.getBatUidOfProjectId(ContextUtil.getProjectId(), list.size());
        if (CollectionUtil.isEmpty(ids)) {
            throw new RuntimeException("System exception, generate snowflake id error");
        }
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setId(ids.get(i));
            list.get(i).setLanguageType(copyToLanguage.name());
        }
        saveBatch(list);

        return R.success(Boolean.TRUE);
    }

    private R<String> getValueStr(String keyword, Object obj, Class<?> clazz) {
        String value = "";
        String methodKey = StringUtils.capitalize(keyword);
        Method method = null;
        try {
            method = clazz.getDeclaredMethod(ConfigContant.METHOD_GET + methodKey, null);
        } catch (NoSuchMethodException e) {
            log.error(e.getMessage());
            return R.fail(e.getMessage());
        }
        Object object = null;
        try {
            object = method.invoke(JSON.parseObject(JSON.toJSONString(obj), clazz));
        } catch (IllegalAccessException | InvocationTargetException e) {
            log.error(e.getMessage());
            return R.fail(e.getMessage());
        }
        if (Objects.isNull(object)) {
            object = "";
        }
        return R.success(object.toString());
    }
}
